﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Mysoft.QuickCode.DbExpressionExtensions
{
    /// <summary>
    /// 更新条件用解析类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class UpdatePartialEvaluator<T> : PartialEvaluator
        where T : class
    {
        private EntityTable<T> entityTable;
        private Stack<KeyValuePair<string, object>> parameters = new Stack<KeyValuePair<string, object>>();

        public UpdatePartialEvaluator(EntityTable<T> entityTable)
            : base()
        {
            this.entityTable = entityTable;
        }

        /// <summary>
        /// 获取解析出来的参数字段的值
        /// </summary>
        /// <returns></returns>
        public Stack<KeyValuePair<string, object>> GetParameters()
        {
            return parameters;
        }
        
        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            switch (m.Method.Name)
            {
                case "ToString":
                    {
                        return this.Visit(m.Object);
                    }
            }
            return base.VisitMethodCall(m);
        }

        //属性值访问字段转换数据库字段
        protected override Expression VisitMemberAccess(MemberExpression m)
        {
            return Expression.Parameter((m.Member as PropertyInfo).PropertyType, entityTable.PropertyToFileds[m.Member.Name]);
        }

        /// <summary>
        /// 2015年7月11日
        /// </summary>
        /// <param name="u"></param>
        /// <returns></returns>
        protected override Expression VisitUnary(UnaryExpression u)
        {
            Expression operand = this.Visit(u.Operand);
            if (operand != u.Operand)
            {
                if (u.NodeType == ExpressionType.Convert)
                {
                    /// 将Linq中的Convert剔除，为了支持表达式中如下语法：
                    /// m.UserName + Age/5，此语法会转为 UserName + Convert((Age/5)) 的SQL语句，导致SQL并不支持。
                    return Expression.Parameter(typeof(string), operand.ToString());
                }
                return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method);
            }
            return u;
        }

        protected override Expression Evaluate(Expression e)
        {
            LambdaExpression lambda = Expression.Lambda(e);
            Delegate fn = lambda.Compile();

            ConstantExpression ce = base.Evaluate(e) as ConstantExpression;
            //不可直接转换为值对象的表达式
            string para = string.Format("p{0}", entityTable.Parameters.Count + parameters.Count);   //将参数按序号生成，防止重复
            //添加参数到entityTable对象的参数集合中
            parameters.Push(new KeyValuePair<string, object>(para, ce.Value ?? DBNull.Value));
            //保存值后，生成值对应的参数
            return Expression.Parameter(ce.Type, string.Format("@{0}", para));
        }
    }
}
